using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    class LandRegionState : RegionState
    {
        public enum FieldFortificationLevel
        {
            none,
            fieldfortification,
            sovietheavyfieldfortification,
        }

        public enum NewBattleStatus
        {
            notNew,
            newBattle,
            newMaginotBattle,
            newMaginotAndRiverAgainstInfBattle,
            newMaginotAndRiverAgainstArmorBattle,
            newMaginotAndRiverAgainstInfAndArmorBattle,
            newRiverCrossingAgainstInfBattle,
            newRiverCrossingAgainstArmorBattle,
            newRiverCrossingAgainstInfAndArmorBattle,
            newAmphibiousBattle,
            newAirborneBattle,
        }

        private bool beachHead = false;
        private MapInfo.CountryID beachHeadCountry = MapInfo.CountryID.GreatBritain;
        private NewBattleStatus newBattleStatus = NewBattleStatus.notNew;
        //TODO we also need to store what GSU arrived by ship during an amphibious landing see 7.23
        private List<Block> blocksInRegion;
        private List<GroundSupportUnit> GSUInRegion;
        private FieldFortificationLevel fieldfortificationlevel;
        private MapInfo.CountryID countryControl;

        public LandRegionState(MapInfo.RegionID regionID)
        {
            this.regionID = regionID;
            blocksInRegion = new List<Block>();
            GSUInRegion = new List<GroundSupportUnit>();
            fieldfortificationlevel = FieldFortificationLevel.none;
        }

        public MapInfo.CountryID BeachHeadCountry
        {
            get
            {
                return beachHeadCountry;
            }

            set
            {
                beachHeadCountry = value;
            }
        }

        public bool NewBattle
        {
            get
            {
                return newBattleStatus != NewBattleStatus.notNew;
            }

            set
            {
                if (value)
                    newBattleStatus = NewBattleStatus.newBattle;
                else
                    newBattleStatus = NewBattleStatus.notNew;
            }
        }

        public NewBattleStatus NewBattleState
        {
            get
            {
                return newBattleStatus;
            }

            set
            {
                newBattleStatus = value;
            }
        }

        public bool BeachHead
        {
            get
            {
                return beachHead;
            }

            set
            {
                beachHead = value;
            }
        }

        public MapInfo.CountryID CountryControl
        {
            get
            {
                return countryControl;
            }

            set
            {
                countryControl = value;
            }
        }

        public FieldFortificationLevel FortLevel
        {
            get
            {
                return fieldfortificationlevel;
            }

            set
            {
                fieldfortificationlevel = value;
            }
        }

        public Block GetBlockAt(int iIndex)
        {
            if (iIndex < blocksInRegion.Count)
                return blocksInRegion[iIndex];
            else
                return null;
        }

        public GroundSupportUnit GetGSUAt(int iIndex)
        {
            if (iIndex < GSUInRegion.Count)
                return GSUInRegion[iIndex];
            else
                return null;
        }

        public PlayingPiece GetPlayingPieceAt(int iIndex)
        {
            if (iIndex < blocksInRegion.Count)
                return blocksInRegion[iIndex];
            else if ((iIndex - blocksInRegion.Count) < GSUInRegion.Count)
                return GSUInRegion[iIndex - blocksInRegion.Count];
            else
                return null;
        }

        public void AddBlock(Block block)
        {
            if(block != null)
                blocksInRegion.Add(block);
        }

        public Block RemoveBlock(MapInfo.CountryID country,Block.BlockType blockType,int currentStrength,int maxStrength,bool bOOS)
        {
            foreach (Block block in blocksInRegion)
            {
                if(country == block.CountryOwner)
                    if(blockType == block.getBlockType())
                        if(currentStrength == block.CurrentStrength)
                            if(maxStrength == block.MaxStrength)
                                if(bOOS == block.OutOfSupply)
                                {
                                    blocksInRegion.Remove(block);
                                    return block;
                                }
            }
            return null;
        }

        public bool RemoveBlock(Block blockToRemove)
        {
            foreach (Block block in blocksInRegion)
            {
                if(block == blockToRemove)
                {
                    blocksInRegion.Remove(block);
                    return true;
                }
            }
            return false;
        }

        public void ReturnPlayingPieceToForcePool(GameState gameState, PlayingPiece playingPieceToReturn)
        {
            if(playingPieceToReturn is Block)
            {
                Block blockToReturn = RemoveBlock(playingPieceToReturn.CountryOwner, ((Block)playingPieceToReturn).getBlockType(), (int)((Block)playingPieceToReturn).CurrentStrength, (int)((Block)playingPieceToReturn).MaxStrength, ((Block)playingPieceToReturn).OutOfSupply);
                if (blockToReturn != null)
                {
                    gameState.ReturnPlayingPieceToForcePool(blockToReturn);
                }
            }
            else
            {
                GroundSupportUnit GSUToReturn = RemoveGSU(playingPieceToReturn.CountryOwner, playingPieceToReturn.OutOfSupply);
                if(GSUToReturn != null)
                {
                    gameState.ReturnPlayingPieceToForcePool(GSUToReturn);
                }
            }
        }

        public void AddGSU(GroundSupportUnit GSU)
        {
            if (GSU != null)
                GSUInRegion.Add(GSU);
        }

        public GroundSupportUnit RemoveGSU(MapInfo.CountryID country, bool OOS)
        {
            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if(country == GSU.CountryOwner && GSU.OutOfSupply == OOS)
                {
                    GSUInRegion.Remove(GSU);
                    return GSU;
                }
            }

            return null;
        }

        public void SetAllCountryPlayingPiecesAsSupplied(GameState gameState,MapInfo.CountryID country)
        {
            foreach (Block block in blocksInRegion)
            {
                if (block.CountryOwner == country)
                    block.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (GSU.CountryOwner == country)
                    GSU.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }
        }

        public void SetAllAxisPlayingPiecesAsSupplied(GameState gameState)
        {
            foreach(Block block in blocksInRegion)
            {
                if (gameState.IsAxisCountry(block.CountryOwner))
                    block.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (gameState.IsAxisCountry(GSU.CountryOwner))
                    GSU.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }
        }

        public void SetAllAlliedPlayingPiecesAsSupplied(GameState gameState)
        {
            foreach (Block block in blocksInRegion)
            {
                if (gameState.IsAlliedCountry(block.CountryOwner))
                    block.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (gameState.IsAlliedCountry(GSU.CountryOwner))
                    GSU.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
            }
        }

        public override void SetAllAxisPlayingPiecesAsUnSupplied(GameState gameState)
        {
            foreach (Block block in blocksInRegion)
            {
                if (gameState.IsAxisCountry(block.CountryOwner) && block.CountryOwner != MapInfo.CountryID.VichyFrance) //Vichy always in supply
                {
                    if (!block.OutOfSupply)
                        block.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                }
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (gameState.IsAxisCountry(GSU.CountryOwner))
                {
                    if (!GSU.OutOfSupply)
                        GSU.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                }
            }
        }

        public override void SetAllAlliedPlayingPiecesAsUnSupplied(GameState gameState)
        {
            foreach (Block block in blocksInRegion)
            {
                if (gameState.IsAlliedCountry(block.CountryOwner))
                {
                    if (!block.OutOfSupply)
                        block.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                }
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (gameState.IsAlliedCountry(GSU.CountryOwner))
                {
                    if (!GSU.OutOfSupply)
                        GSU.OutOfSupplyState = PlayingPiece.OOSState.OOS;
                }
            }
        }

        public int GetNumberOfPlayingPiecesByCountry(MapInfo.CountryID country)
        {
            int numberofPieces = 0;
            foreach (Block block in blocksInRegion)
            {
                if (block.CountryOwner == country)
                    numberofPieces++;
            }

            foreach (GroundSupportUnit GSU in GSUInRegion)
            {
                if (GSU.CountryOwner == country)
                    numberofPieces++;
            }
            return numberofPieces;
        }

        public bool AnyAxisBlocksRemaining(GameState gameState)
        {
            foreach (Block block in blocksInRegion)
            {
                if (gameState.IsAxisCountry(block.CountryOwner))
                    return true;
            }
            return false;
        }

        public bool AnyAlliedBlocksRemaining(GameState gameState)
        {
            foreach (Block block in blocksInRegion)
            {
                if (gameState.IsAlliedCountry(block.CountryOwner))
                    return true;
            }
            return false;
        }

        public bool AnyAxisGSURemaining(GameState gameState)
        {
            foreach (GroundSupportUnit gsu in GSUInRegion)
            {
                if (gameState.IsAxisCountry(gsu.CountryOwner))
                    return true;
            }
            return false;
        }

        public bool AnyAlliedGSURemaining(GameState gameState)
        {
            foreach (GroundSupportUnit gsu in GSUInRegion)
            {
                if (gameState.IsAlliedCountry(gsu.CountryOwner))
                    return true;
            }
            return false;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("LandRegionState");
            System.Xml.XmlAttribute regionIDAttr = xml.CreateAttribute("RegionID");
            System.Xml.XmlAttribute countryControlAttr = xml.CreateAttribute("CountryControl");
            System.Xml.XmlAttribute fortificationAttr = xml.CreateAttribute("Fortification");
            System.Xml.XmlAttribute newBattleStatusAttr = xml.CreateAttribute("NewBattleStatus");
            System.Xml.XmlAttribute beachHeadAttr = xml.CreateAttribute("BeachHead");
            System.Xml.XmlAttribute beachHeadCountryAttr = xml.CreateAttribute("BeachHeadCountry");
            regionIDAttr.Value = Enum.GetName(typeof(MapInfo.RegionID),this.regionID);
            countryControlAttr.Value = Enum.GetName(typeof(MapInfo.CountryID),this.countryControl);
            fortificationAttr.Value = Enum.GetName(typeof(FieldFortificationLevel),this.fieldfortificationlevel);
            newBattleStatusAttr.Value = Enum.GetName(typeof(NewBattleStatus),this.newBattleStatus);
            beachHeadCountryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), this.beachHeadCountry);
            beachHeadAttr.Value = beachHead.ToString();
            nodeToReturn.Attributes.Append(regionIDAttr);
            nodeToReturn.Attributes.Append(countryControlAttr);
            nodeToReturn.Attributes.Append(fortificationAttr);
            nodeToReturn.Attributes.Append(newBattleStatusAttr);
            nodeToReturn.Attributes.Append(beachHeadAttr);
            nodeToReturn.Attributes.Append(beachHeadCountryAttr);

            foreach(Block block in blocksInRegion)
            {
                nodeToReturn.AppendChild(block.Serialise(xml));
            }

            foreach(GroundSupportUnit GSU in GSUInRegion)
            {
                nodeToReturn.AppendChild(GSU.Serialise(xml));
            }

            return nodeToReturn;
        }

        public static new RegionState Deserialise(System.Xml.XmlNode node)
        {
            LandRegionState landRegionStateToReturn = new LandRegionState((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["RegionID"].Value));

            landRegionStateToReturn.countryControl = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID),node.Attributes["CountryControl"].Value);
            landRegionStateToReturn.fieldfortificationlevel = (FieldFortificationLevel)Enum.Parse(typeof(FieldFortificationLevel),node.Attributes["Fortification"].Value);
            landRegionStateToReturn.newBattleStatus = (NewBattleStatus)Enum.Parse(typeof(NewBattleStatus),node.Attributes["NewBattleStatus"].Value);
            landRegionStateToReturn.beachHead = bool.Parse(node.Attributes["BeachHead"].Value);
            landRegionStateToReturn.beachHeadCountry = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["BeachHeadCountry"].Value);
            foreach(System.Xml.XmlNode landRegionStateNode in node)
            {
                switch(landRegionStateNode.Name)
                {
                    case "Block":
                        landRegionStateToReturn.blocksInRegion.Add(Block.Deserialise(landRegionStateNode));
                        break;
                    case "GSU":
                        landRegionStateToReturn.GSUInRegion.Add(GroundSupportUnit.Deserialise(landRegionStateNode));
                        break;
                }
            }

            return landRegionStateToReturn;
        }

        public override bool Equals(RegionState regionStateToCompare)
        {
            if (regionStateToCompare is LandRegionState)
            {
                LandRegionState landRegionStateToCompare = (LandRegionState)regionStateToCompare;

                if (this.countryControl != landRegionStateToCompare.countryControl)
                    return false;
                if (this.fieldfortificationlevel != landRegionStateToCompare.fieldfortificationlevel)
                    return false;
                if (this.regionID != landRegionStateToCompare.regionID)
                    return false;
                if (this.newBattleStatus != landRegionStateToCompare.newBattleStatus)
                    return false;
                if (this.blocksInRegion.Count != landRegionStateToCompare.blocksInRegion.Count)
                    return false;
                if (this.beachHeadCountry != landRegionStateToCompare.beachHeadCountry)
                    return false;

                List<Block> listOfBlocksToCompare = new List<Block>(landRegionStateToCompare.blocksInRegion);
                foreach (Block block in this.blocksInRegion)
                {
                    bool found = false;
                    foreach (Block blockToLookFor in listOfBlocksToCompare)
                    {
                        if (block.Equals(blockToLookFor))
                        {
                            found = true;
                            listOfBlocksToCompare.Remove(blockToLookFor);
                            break;
                        }
                    }
                    if (!found)
                        return false;
                }

                if (this.GSUInRegion.Count != landRegionStateToCompare.GSUInRegion.Count)
                    return false;
                List<GroundSupportUnit> listOfGSUToCompare = new List<GroundSupportUnit>(landRegionStateToCompare.GSUInRegion);
                foreach (GroundSupportUnit GSU in this.GSUInRegion)
                {
                    bool found = false;
                    foreach (GroundSupportUnit GSUToLookFor in listOfGSUToCompare)
                    {
                        if (GSU.Equals(GSUToLookFor))
                        {
                            found = true;
                            listOfGSUToCompare.Remove(GSUToLookFor);
                            break;
                        }
                    }
                    if (!found)
                        return false;
                }

                return true;
            }
            else
                return false;
        }

        public bool IsContested(GameState gameState)
        {
            if(AnyAlliedBlocksRemaining(gameState))
            {
                if (AnyAxisBlocksRemaining(gameState))
                    return true;
            }

            return false;
        }

        public bool IsEnemyControlled(GameState gameState, GameController.playerType playerType)
        {
            if(playerType == GameController.playerType.AxisPlayer)
            {
                if (gameState.IsAlliedCountry(this.countryControl))
                    return true;
                return false;
            }
            else
            {
                if (gameState.IsAxisCountry(this.countryControl))
                    return true;
                return false;
            }
        }

        public bool IsFriendlyControlled(GameState gameState, GameController.playerType playerType)
        {
            if (playerType == GameController.playerType.AxisPlayer)
            {
                if (gameState.IsAxisCountry(this.countryControl))
                    return true;
                return false;
            }
            else
            {
                if (gameState.IsAlliedCountry(this.countryControl))
                    return true;
                return false;
            }
        }

        public void RemoveAllUnitsOfCountry(GameState gameState, MapInfo.CountryID countryID)
        {
            bool loop = true;
            while (loop)
            {
                loop = false;
                for (int i = 0; GetPlayingPieceAt(i) != null; i++)
                {
                    PlayingPiece piece = GetPlayingPieceAt(i);
                    if (piece.CountryOwner == countryID)
                    {
                        this.ReturnPlayingPieceToForcePool(gameState, piece);
                        loop = true;
                        break;
                    }
                }
            }
        }

        public void RemoveGSUAndBeachHeadsAloneWithGroundUnits(GameState gameState)
        {
            bool regionContainsAxisBlocks = false;
            bool regionContainsAlliedBlocks = false;
            bool regionContainsAxisGSU = false;
            bool regionContainsAlliedGSU = false;

            for(int i = 0; GetPlayingPieceAt(i) != null; i++)
            {
                PlayingPiece piece = GetPlayingPieceAt(i);
                if(piece is Block)
                {
                    if(gameState.IsAxisCountry(piece.CountryOwner))
                    {
                        regionContainsAxisBlocks = true;
                    }
                    else if(gameState.IsAlliedCountry(piece.CountryOwner))
                    {
                        regionContainsAlliedBlocks = true;
                    }
                }
                else if(piece is GroundSupportUnit)
                {
                    if (gameState.IsAxisCountry(piece.CountryOwner))
                    {
                        regionContainsAxisGSU = true;
                    }
                    else if (gameState.IsAlliedCountry(piece.CountryOwner))
                    {
                        regionContainsAlliedGSU = true;
                    }
                }
            }

            if (regionContainsAlliedBlocks && !regionContainsAxisBlocks && this.BeachHead && gameState.IsAxisCountry(this.beachHeadCountry))
            {
                gameState.RemoveBeachHead(this.RegionID);
            }

            if (regionContainsAxisBlocks && !regionContainsAlliedBlocks && this.BeachHead && gameState.IsAlliedCountry(this.beachHeadCountry))
            {
                gameState.RemoveBeachHead(this.RegionID);
            }

            if(regionContainsAlliedBlocks && !regionContainsAxisBlocks && regionContainsAxisGSU)
            {
                bool loop = true;
                while(loop)
                {
                    loop = false;
                    for (int i = 0; GetPlayingPieceAt(i) != null; i++)
                    {
                        PlayingPiece piece = GetPlayingPieceAt(i);
                        if (gameState.IsAxisCountry(piece.CountryOwner))
                        {
                            if (piece is GroundSupportUnit)
                            {
                                this.ReturnPlayingPieceToForcePool(gameState, piece);
                                loop = true;
                                break;
                            }
                        }
                    }
                }
            }
            else if(regionContainsAxisBlocks && !regionContainsAlliedBlocks && regionContainsAlliedGSU)
            {
                bool loop = true;
                while (loop)
                {
                    loop = false;
                    for (int i = 0; GetPlayingPieceAt(i) != null; i++)
                    {
                        PlayingPiece piece = GetPlayingPieceAt(i);
                        if (gameState.IsAlliedCountry(piece.CountryOwner))
                        {
                            if (piece is GroundSupportUnit)
                            {
                                this.ReturnPlayingPieceToForcePool(gameState, piece);
                                loop = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}
